package com.md.api.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.md.api.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpClientUtils {

	private HttpClientUtils(){}
	
	// 常用浏览器的"User-Agent"值
	public static final String PC_GOOGLE = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36";
	public static final String PC_FIREFOX = "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0";
	public static final String PC_IE = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";
	public static final String IPAD_SYSTEM = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10";
	public static final String ANDROID_UC = "JUC (Linux; U; 2.3.7; zh-cn; MB200; 320*480) UCWEB7.9.3.103/139/999";

	// "parameters" Map集合编码格式key标示协议
	public static final String CHARSET = "char_set_9527";
	public static final String RESULT_STATUS = "status";
	public static final String RESULT_CONTENT = "content";

	// 默认编码
	public static final String DEFUALT_CHARSET = "UTF-8";

	private static RequestConfig config = HttpClientUtils.getRequestConfig(null, false).build();

	/**
	 * 请求代理配置
	 * 
	 * @param builder
	 *            可为null,为null时实例化新的配置对象
	 * @param ip
	 *            ip地址
	 * @param port
	 *            端口
	 * @return
	 */
	public static RequestConfig.Builder getRequestConfig(RequestConfig.Builder builder, String ip, int port) {
		if (builder == null) {
			builder = RequestConfig.custom();
		}
		HttpHost proxy = new HttpHost(ip, port);
		return builder.setProxy(proxy);
	}
	
	/**
	 * 设置RequestConfig是否自动重定向的配置对象（默认get请求自动重定向、post请求无法设置）
	 * 
	 * @param builder
	 *            可为null,为null时实例化新的配置对象
	 * @param redirectsEnabled
	 *            是否自动重定向的配置对象
	 * @return
	 */
	public static RequestConfig.Builder getRequestConfig(RequestConfig.Builder builder, boolean redirectsEnabled) {
		if (builder == null) {
			builder = RequestConfig.custom();
		}
		return builder.setSocketTimeout(15000).setConnectTimeout(15000).setConnectionRequestTimeout(30000).setRedirectsEnabled(redirectsEnabled);
	}

	/**
	 * 设置超时时间
	 * 
	 * @param connectionRequestTimeout
	 *            默认连接池获取超时毫秒数
	 * @param connectTimeout
	 *            默认连接超时毫秒数
	 * @param socketTimeout
	 *            默认读取数据超时毫秒数
	 * @return
	 */
	public static RequestConfig.Builder getRequestConfig(RequestConfig.Builder builder, int connectionRequestTimeout, int connectTimeout, int socketTimeout) {
		if (builder == null) {
			builder = RequestConfig.custom();
		}
		return builder.setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectionRequestTimeout);
	}

	/**
	 * 简易的get请求
	 * @param url
	 * @param config
	 * @param userAgent
	 * @param parameters
	 * @param cookies
	 * @return
	 * @throws IOException 
	 * @throws ClientProtocolException 
	 * @throws Exception
	 */
	public static void simpleGet(String url,String userAgent, RequestConfig config, Map<String, String> parameters, List<BasicClientCookie> cookies) throws ClientProtocolException, IOException{
		
		CloseableHttpClient httpClient = null;
		BasicCookieStore cookieStore = null;
		if (cookies != null) {
			cookieStore = new BasicCookieStore();
			httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
		} else {
			httpClient = HttpClients.createDefault();
		}

		// 组装参数、设置头
		HttpGet request = null;
		// from表单提交get请求自动切除?后的参数
		if (parameters != null && parameters.size() != 0) {
			String charset = (parameters.containsKey(HttpClientUtils.CHARSET) ? parameters.get(HttpClientUtils.CHARSET) : HttpClientUtils.DEFUALT_CHARSET);
			
			StringBuilder _url = new StringBuilder(url);
			if (url.indexOf("?") == -1 ) {
				_url.append("?");
			}
			for (String key : parameters.keySet()) {
				if (key.equals(HttpClientUtils.CHARSET)) {
					continue;
				}
				_url.append("&").append(key).append("=").append(URLEncoder.encode(parameters.get(key), charset));
			}
			request = new HttpGet(_url.toString().indexOf("?&")==-1?_url.toString():_url.toString().replaceFirst("\\?&", "\\?"));
		} else {
			request = new HttpGet(url);
		}
		// 设置cookie
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				cookieStore.addCookie(cookie);
			}
		}
		request.setConfig(config);
		request.setHeader("User-Agent", userAgent);
		// 发送请求
		httpClient.execute(request).close();
		httpClient.close();
	}
	
	public static Map<String, String> simpleGet(String url) throws ClientProtocolException, IOException {
		return get(url, null, null, null, null, null);
	}
	
	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            请求地址
	 * @param config
	 *            请求配置（超时设置/代理）
	 * @param userAgent
	 *            需要模拟浏览器的userAgent值
	 * @throws IOException 
	 * @throws ClientProtocolException 
	 * @throws Exception
	 */
	public static Map<String, String> get(String url, RequestConfig config, String userAgent, Map<String, String> parameters, List<BasicClientCookie> cookies, String responseCharSet) throws ClientProtocolException, IOException {

		CloseableHttpClient httpClient = null;
		BasicCookieStore cookieStore = null;
		if (cookies != null) {
			cookieStore = new BasicCookieStore();
			httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
		} else {
			httpClient = HttpClients.createDefault();
		}

		// 组装参数、设置头
		HttpGet request = null;
		Map<String, String> result = new HashMap<String, String>();
		// from表单提交get请求自动切除?后的参数
		if (parameters != null && parameters.size() != 0) {
			String charset = (parameters.containsKey(HttpClientUtils.CHARSET) ? parameters.get(HttpClientUtils.CHARSET) : HttpClientUtils.DEFUALT_CHARSET);
			
			StringBuilder _url = new StringBuilder(url);
			if (url.indexOf("?") == -1 ) {
				_url.append("?");
			}
			for (String key : parameters.keySet()) {
				if (key.equals(HttpClientUtils.CHARSET)) {
					continue;
				}
				_url.append("&").append(key).append("=").append(URLEncoder.encode(parameters.get(key), charset));
			}
			request = new HttpGet(_url.toString().indexOf("?&")==-1?_url.toString():_url.toString().replaceFirst("\\?&", "\\?"));
		} else {
			request = new HttpGet(url);
		}
		// 设置cookie
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				cookieStore.addCookie(cookie);
			}
		}
		if (config != null) {
			request.setConfig(config);
		}
		request.setHeader("User-Agent", userAgent);

		// 发送请求
		CloseableHttpResponse response = httpClient.execute(request);
		HttpEntity entity = response.getEntity();

		if (cookies != null) {
			List<Cookie> _cookies = cookieStore.getCookies();
			if (_cookies.isEmpty()) {
				System.out.println("None");
			} else {
				cookies.clear();
				for (int i = 0; i < _cookies.size(); i++) {
					cookies.add((BasicClientCookie) _cookies.get(i));
				}
			}
		}
		switch (response.getStatusLine().getStatusCode()) {
		case 200:
			if (entity != null) {
				result.put(RESULT_STATUS, "200");
				result.put(RESULT_CONTENT, EntityUtils.toString(entity, responseCharSet == null ? DEFUALT_CHARSET : responseCharSet));
			}
			break;
		case 302:
			if (entity != null) {
				result.put(RESULT_STATUS, "302");
				result.put(RESULT_CONTENT, EntityUtils.toString(entity, responseCharSet == null ? DEFUALT_CHARSET : responseCharSet));
			}
			break;
		case 500:
		case 501:
		case 502:
		case 503:
		case 504:
		case 505:
			if (entity != null) {
				throw new BusinessException(500, "服务器端发生异常: " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new BusinessException(500, "服务器端发生异常!");
		case 403:
			if (entity != null) {
				throw new BusinessException(403, "访问被拒绝 : " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new BusinessException(403, "访问被拒绝 !");
		case 404:
			if (entity != null) {
				throw new BusinessException(404, "访问的资源不存在: " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new BusinessException(404, "访问的资源不存在!");
		default:
			if (entity != null) {
				throw new RuntimeException("预料之外的异常: " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new RuntimeException("预料之外的异常! ");
		}
		response.close();
		httpClient.close();
		return result;
	}

	public static String postJson(String url, JSONObject json) throws ClientProtocolException, IOException{
		String jsonStr = json.toJSONString();
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
        // 解决中文乱码问题
        StringEntity stringEntity = new StringEntity(jsonStr, DEFUALT_CHARSET);
        stringEntity.setContentEncoding(DEFUALT_CHARSET);
        httpPost.setEntity(stringEntity);
        ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
            @Override
            public String handleResponse(final HttpResponse response)
                    throws ClientProtocolException, IOException {
                int status = response.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity entity = response.getEntity();
                    return entity != null ? EntityUtils.toString(entity) : null;
                } else {
                    throw new ClientProtocolException("Unexpected response status: " + status);
                }
            }
        };
        return httpclient.execute(httpPost, responseHandler);
	}
	
	public static String postXML(String url,String xml){
        CloseableHttpClient client = null;
        CloseableHttpResponse resp = null;
        try{
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "text/xml; charset=UTF-8");
            StringEntity entityParams = new StringEntity(xml,"utf-8");
            httpPost.setEntity(entityParams);
            client = HttpClients.createDefault();
            resp = client.execute(httpPost);
            String resultMsg = EntityUtils.toString(resp.getEntity(),"utf-8");
            return resultMsg;
        }catch (Exception e){
        	log.error("postXML", e);
        }finally {
            try {
                if(client!=null){
                    client.close();
                }
                if(resp != null){
                    resp.close();
                }
            } catch (IOException e) {
            }
        }
        return null;
    }

	/**
	 * 发送post请求
	 * 
	 * @param url
	 *            请求地址
	 * @param config
	 *            请求配置（超时设置/代理）
	 * @param userAgent
	 *            需要模拟浏览器的userAgent值
	 * @throws Exception
	 */
	public static Map<String, String> post(String url,String referer, String userAgent, Map<String, String> parameters, List<Cookie> cookies, String responseCharSet) throws Exception {

		CloseableHttpClient httpClient = null;
		BasicCookieStore cookieStore = null;
		if (cookies != null) {
			cookieStore = new BasicCookieStore();
			httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
		} else {
			httpClient = HttpClients.createDefault();
		}

		Map<String, String> result = new HashMap<String, String>();
		HttpPost request = null;
		if (parameters != null && parameters.size() != 0) {
			List<NameValuePair> formParameters = new ArrayList<NameValuePair>();
			String charset = (parameters.containsKey(HttpClientUtils.CHARSET) ? parameters.get(HttpClientUtils.CHARSET) : HttpClientUtils.DEFUALT_CHARSET);
			for (String key : parameters.keySet()) {
				if (key.equals(HttpClientUtils.CHARSET)) {
					continue;
				}
				formParameters.add(new BasicNameValuePair(key, parameters.get(key)));
			}
			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParameters, charset);
			request = new HttpPost(url);
			request.setEntity(entity);
		} else {
			request = new HttpPost(url);
		}
		request.setConfig(config);
		// 设置cookie
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				cookieStore.addCookie(cookie);
			}
		}
		if (referer != null) {
			request.setHeader("Referer", referer);
		}
		request.setHeader("User-Agent", userAgent);
		
		CloseableHttpResponse response = httpClient.execute(request);
		HttpEntity entity = response.getEntity();
		if (cookies != null) {
			List<Cookie> _cookies = cookieStore.getCookies();
			if (!_cookies.isEmpty()) {
				cookies.clear();
				for (int i = 0; i < _cookies.size(); i++) {
					System.out.println(_cookies.get(i).getDomain());
					System.out.println(_cookies.get(i).getPath());
					System.out.println(_cookies.get(i).getName());
					System.out.println(_cookies.get(i).getValue());
					cookies.add(_cookies.get(i));
				}
			}
		}
		switch (response.getStatusLine().getStatusCode()) {
		case 200:
			if (entity != null) {
				result.put(RESULT_STATUS, "200");
				result.put(RESULT_CONTENT, EntityUtils.toString(entity, responseCharSet == null ? DEFUALT_CHARSET : responseCharSet));
			}
			break;
		case 302:
			if (entity != null) {
				result.put(RESULT_STATUS, "302");
				result.put(RESULT_CONTENT, EntityUtils.toString(entity, responseCharSet == null ? DEFUALT_CHARSET : responseCharSet));
			}
			break;
		case 500:
		case 501:
		case 502:
		case 503:
		case 504:
		case 505:
			if (entity != null) {
				throw new RuntimeException("服务器端发生异常: " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new RuntimeException("服务器端发生异常!");
		case 403:
			if (entity != null) {
				throw new RuntimeException("访问被拒绝 : " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new RuntimeException("访问被拒绝 !");
		case 404:
			if (entity != null) {
				throw new RuntimeException("访问的资源不存在: " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new RuntimeException("访问的资源不存在!");
		default:
			if (entity != null) {
				throw new RuntimeException("预料之外的异常: " + EntityUtils.toString(entity, "GB2312"));
			}
			throw new RuntimeException("预料之外的异常! ");
		}
		response.close();
		httpClient.close();
		return result;
	}
	
	public static boolean downloadFile(String remoteFileUrl, String localFilePath) throws ClientProtocolException, IOException {
        CloseableHttpResponse response = null;
        InputStream in = null;
        FileOutputStream fout = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpGet httpget = new HttpGet(remoteFileUrl);
            response = httpClient.execute(httpget);
            HttpEntity entity = response.getEntity();
            if (entity == null) {
                return false;
            }
            in = entity.getContent();
            File file = new File(localFilePath);
            fout = new FileOutputStream(file);
            int l;
            byte[] tmp = new byte[1024];
            while ((l = in.read(tmp)) != -1) {
                fout.write(tmp, 0, l);
                // 注意这里如果用OutputStream.write(buff)的话，图片会失真
            }
            // 将文件输出到本地
            fout.flush();
            EntityUtils.consume(entity);
            return true;
        } finally {
            // 关闭低层流。
            if (fout != null) {
                try {
                    fout.close();
                } catch (Exception e) {
                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (Exception e) {
                }
            }
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (Exception e) {
                }
            }
        }
    }

	public static InputStream downloadFile(String remoteFileUrl) throws ClientProtocolException, IOException {
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpGet httpget = new HttpGet(remoteFileUrl);
            response = httpClient.execute(httpget);
            HttpEntity entity = response.getEntity();
            return entity.getContent();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (Exception e) {
                }
            }
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (Exception e) {
                }
            }
        }
    }
	
	public static void main(String[] args) {
		try {
			CloseableHttpClient client = HttpClients.createDefault();
			HttpPost post = new HttpPost("https://app.gsxt.gov.cn/gsxt/corp-query-app-search-1.html");
			Map<String, String> headrs = new HashMap<String, String>();
			headrs.put("Accept", "application/json");
			headrs.put("Accept-Encoding", "gzip, deflate, br");
			headrs.put("Accept-Language", "zh-CN,zh;q=0.8");
			headrs.put("Cache-Control", "no-cache");
			headrs.put("Connection", "keep-alive");
			headrs.put("Content-Type", "application/x-www-form-urlencoded");
			headrs.put("Origin", "http://127.0.0.1:34664");
			headrs.put("Pragma", "no-cache");
			headrs.put("Referer", "https://servicewechat.com/page-frame.html");
			headrs.put("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 wechat/1.02.1902010 MicroMessenger/6.7.3 Language/zh_CN webview");
			for (String key : headrs.keySet()) {
				post.addHeader(key, headrs.get(key));
			}
			List<NameValuePair> params = new ArrayList<NameValuePair>();
			NameValuePair conditions = new BasicNameValuePair("conditions", "{\"excep_tab\":\"0\",\"ill_tab\":\"0\",\"area\":\"0\",\"cStatus\":\"0\",\"xzxk\":\"0\",\"xzcf\":\"0\",\"dydj\":\"0\"}");
			NameValuePair searchword = new BasicNameValuePair("searchword","重庆梦道科技有限公司");
			NameValuePair sourceType = new BasicNameValuePair("sourceType","W");
			params.add(conditions);
			params.add(searchword);
			params.add(sourceType);
			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, HttpClientUtils.DEFUALT_CHARSET);
			post.setEntity(entity);
			CloseableHttpResponse response = client.execute(post);
			String content = EntityUtils.toString(response.getEntity(), HttpClientUtils.DEFUALT_CHARSET);
			System.out.println(content);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
